home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 March
/
EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso
/
earcd
/
gnu
/
gnpltsrc.lha
/
graph3d.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-22
|
55KB
|
1,914 lines
#ifndef lint
static char *RCSid = "$Id: graph3d.c,v 1.85 1995/12/02 22:04:32 drd Exp $";
#endif
/* GNUPLOT - graph3d.c */
/*
* Copyright (C) 1986 - 1993 Thomas Williams, Colin Kelley
*
* Permission to use, copy, and distribute this software and its
* documentation for any purpose with or without fee is hereby granted,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.
*
* Permission to modify the software is granted, but not the right to
* distribute the modified code. Modifications are to be distributed
* as patches to released version.
*
* This software is provided "as is" without express or implied warranty.
*
*
* AUTHORS
*
* Original Software:
* Gershon Elber and many others.
*
* 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
* Added user-specified bases for log scaling.
*
* 3.6 - split graph3d.c into graph3d.c (graph),
* util3d.c (intersections, etc)
* hidden3d.c (hidden-line removal code)
*
* There is a mailing list for gnuplot users. Note, however, that the
* newsgroup
* comp.graphics.gnuplot
* is identical to the mailing list (they
* both carry the same set of messages). We prefer that you read the
* messages through that newsgroup, to subscribing to the mailing list.
* (If you can read that newsgroup, and are already on the mailing list,
* please send a message info-gnuplot-request@dartmouth.edu, asking to be
* removed from the mailing list.)
*
* The address for mailing to list members is
* info-gnuplot@dartmouth.edu
* and for mailing administrative requests is
* info-gnuplot-request@dartmouth.edu
* The mailing list for bug reports is
* bug-gnuplot@dartmouth.edu
* The list of those interested in beta-test versions is
* info-gnuplot-beta@dartmouth.edu
*/
#include <math.h>
#if !defined(sequent) && !defined(apollo) && !defined(alliant)
#include <limits.h>
#endif
#include "plot.h"
#include "setshow.h"
#define KEYWTH ( (int) (4*(t->h_char) + pointsize*(t->h_tic)))
extern TBOOLEAN term_graphics, term_suspended;
static int p_height;
static int p_width; /* pointsize * t->h_tic */
static int key_entry_height; /* bigger of t->v_size, pointsize*t->v_tick */
int suppressMove = 0; /* for preventing moveto while drawing contours */
/*
* hidden_line_type_above, hidden_line_type_below - controls type of lines
* for above and below parts of the surface.
* hidden_no_update - if TRUE lines will be hidden line removed but they
* are not assumed to be part of the surface (i.e. grid) and therefore
* do not influence the hidings.
* hidden_active - TRUE if hidden lines are to be removed.
*/
int hidden_active = FALSE;
/* LITE defines a restricted memory version for MS-DOS, which doesn't
* use the routines in hidden3d.c
*/
#ifndef LITE
int hidden_line_type_above, hidden_line_type_below;
int hidden_no_update;
#endif /* LITE */
static double LogScale __P((double coord, TBOOLEAN is_log, double log_base_log,
char *what, char *axis));
static void plot3d_impulses __P((struct surface_points *plot));
static void plot3d_lines __P((struct surface_points *plot));
static void plot3d_points __P((struct surface_points *plot));
static void plot3d_dots __P((struct surface_points *plot));
static void cntr3d_impulses __P((struct gnuplot_contours *cntr, struct surface_points *plot));
static void cntr3d_lines __P((struct gnuplot_contours *cntr));
static void cntr3d_points __P((struct gnuplot_contours *cntr, struct surface_points *plot));
static void cntr3d_dots __P((struct gnuplot_contours *cntr));
static void check_corner_height __P((struct coordinate GPHUGE *point, double height[2][2], double depth[2][2]));
static void draw_bottom_grid __P((struct surface_points *plot, int plot_count));
static void xtick_callback __P((int axis, double place, char *text, int grid));
static void ytick_callback __P((int axis, double place, char *text, int grid));
static void ztick_callback __P((int axis, double place, char *text, int grid));
static void setlinestyle __P((int style));
static void boundary3d __P((int scaling, struct surface_points *plots, int count));
#if 0 /* not used */
static double dbl_raise __P((double x, int y));
#endif
static void map_position __P((struct position *pos, unsigned int *x, unsigned int *y, char *what));
/* put entries in the key */
static void key_sample_line __P((int xl, int yl));
static void key_sample_point __P((int xl, int yl, int pointtype));
static void key_text __P((int xl, int yl, char *text));
#if defined(sun386) || defined(AMIGA_SC_6_1)
static double CheckLog __P((TBOOLEAN is_log, double base_log, double x));
#endif
#ifndef max /* Lattice C has max() in math.h, but shouldn't! */
#define max(a,b) ((a > b) ? a : b)
#endif
#ifndef min
#define min(a,b) ((a < b) ? a : b)
#endif
/*
* The Amiga SAS/C 6.2 compiler moans about macro envocations causing
* multiple calls to functions. I converted these macros to inline
* functions coping with the problem without loosing speed.
* (MGR, 1993)
*/
#ifdef AMIGA_SC_6_1
__inline static TBOOLEAN i_inrange(int z,int min,int max)
{
return((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)));
}
__inline static double f_max(double a,double b)
{
return(max(a,b));
}
__inline static double f_min(double a,double b)
{
return(min(a,b));
}
#else
#define f_max(a,b) max((a),(b))
#define f_min(a,b) min((a),(b))
#define i_inrange(z,a,b) inrange((z),(a),(b))
#endif
#define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
#define apx_eq(x,y) (fabs(x-y) < 0.001)
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define SQR(x) ((x) * (x))
/* Define the boundary of the plot
* These are computed at each call to do_plot, and are constant over
* the period of one do_plot. They actually only change when the term
* type changes and when the 'set size' factors change.
*/
/* in order to allow graphic.c to use clip_draw_line, we must
* share xleft, xright, ybot, ytop with graphics.c
*/
extern int xleft, xright, ybot, ytop;
int xmiddle, ymiddle, xscaler, yscaler;
static int ptitl_cnt;
static int max_ptitl_len;
static int titlelin;
static int key_rows, key_cols, key_col_wth, yl_ref;
static int ktitle_lines = 0;
/* Boundary and scale factors, in user coordinates */
/* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
* file and are not the same as variables of the same names in other files
*/
/*static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;*/
/* sizes are now set in min_array[], max_array[] from command.c */
extern double min_array[], max_array[];
extern int auto_array[], log_array[];
extern double base_array[], log_base_array[];
/* for convenience while converting to use these arrays */
#define x_min3d min_array[FIRST_X_AXIS]
#define x_max3d max_array[FIRST_X_AXIS]
#define y_min3d min_array[FIRST_Y_AXIS]
#define y_max3d max_array[FIRST_Y_AXIS]
#define z_min3d min_array[FIRST_Z_AXIS]
#define z_max3d max_array[FIRST_Z_AXIS]
/* There are several z's to take into account - I hope I get these
* right !
*
* ceiling_z is the highest z in use
* floor_z is the lowest z in use
* base_z is the z of the base
* min3d_z is the lowest z of the graph area
* max3d_z is the highest z of the graph area
*
* ceiling_z is either max3d_z or base_z, and similarly for floor_z
* There should be no part of graph drawn outside
* min3d_z:max3d_z - apart from arrows, perhaps
*/
double ceiling_z, floor_z, base_z;
/* and some bodges while making the change */
#define min3d_z min_array[FIRST_Z_AXIS]
#define max3d_z max_array[FIRST_Z_AXIS]
double xscale3d, yscale3d, zscale3d;
typedef double transform_matrix[4][4];
transform_matrix trans_mat;
static double xaxis_y, yaxis_x, zaxis_x, zaxis_y;
/* the co-ordinates of the back corner */
static double back_x, back_y;
/* the penalty for convenience of using tic_gen to make callbacks
* to tick routines is that we cant pass parameters very easily.
* We communicate with the tick_callbacks using static variables
*/
/* unit vector (terminal coords) */
static double tic_unitx, tic_unity;
/* (DFK) Watch for cancellation error near zero on axes labels */
#define SIGNIF (0.01) /* less than one hundredth of a tic mark */
#define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
#define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
/* And the functions to map from user to terminal coordinates */
#define map_x(x) (int)(x+0.5) /* maps floating point x to screen */
#define map_y(y) (int)(y+0.5) /* same for y */
/* And the functions to map from user 3D space into normalized -1..1 */
#define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
#define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
#define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
/* Initialize the line style using the current device and set hidden styles */
/* to it as well if hidden line removal is enabled. */
static void setlinestyle(style)
int style;
{
register struct termentry *t = term;
(*t->linetype)(style);
#ifndef LITE
if (hidden3d) {
hidden_line_type_above = style;
hidden_line_type_below = style;
}
#endif /* LITE */
}
#ifndef LITE
#endif /* not LITE */
/* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog
* macro, so I write it as a function on that machine.
*
* Amiga SAS/C 6.2 thinks it will do too much work calling functions in
* macro arguments twice, thus I inline theese functions. (MGR, 1993)
*/
#if defined(sun386) || defined(AMIGA_SC_6_1)
#ifdef AMIGA_SC_6_1
__inline
#endif
static double
CheckLog(is_log, base_log, x)
TBOOLEAN is_log;
double base_log;
double x;
{
if (is_log)
return(pow(base_log, x));
else
return(x);
}
#else
/* (DFK) Use 10^x if logscale is in effect, else x */
#define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
#endif /* sun386 || SAS/C */
static double
LogScale(coord, is_log, log_base_log, what, axis)
double coord; /* the value */
TBOOLEAN is_log; /* is this axis in logscale? */
double log_base_log; /* if so, the log of its base */
char *what; /* what is the coord for? */
char *axis; /* which axis is this for ("x" or "y")? */
{
if (is_log) {
if (coord <= 0.0) {
char errbuf[100]; /* place to write error message */
(void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
what, axis, coord);
graph_error(errbuf);
} else
return(log(coord)/log_base_log);
}
return(coord);
}
/* And the functions to map from user 3D space to terminal coordinates */
void map3d_xy(x, y, z, xt, yt)
double x, y, z;
unsigned int *xt, *yt;
{
int i,j;
double v[4], res[4], /* Homogeneous coords. vectors. */
w = trans_mat[3][3];
v[0] = map_x3d(x); /* Normalize object space to -1..1 */
v[1] = map_y3d(y);
v[2] = map_z3d(z);
v[3] = 1.0;
for (i = 0; i < 2; i++) { /* Dont use the third axes (z). */
res[i] = trans_mat[3][i]; /* Initiate it with the weight factor. */
for (j = 0; j < 3; j++) res[i] += v[j] * trans_mat[j][i];
}
for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
if (w == 0) w = 1e-5;
*xt = (unsigned int) ((res[0] * xscaler / w) + xmiddle);
*yt = (unsigned int) ((res[1] * yscaler / w) + ymiddle);
}
/* And the functions to map from user 3D space to terminal z coordinate */
int map3d_z(x, y, z)
double x, y, z;
{
int i, zt;
double v[4], res, /* Homogeneous coords. vectors. */
w = trans_mat[3][3];
v[0] = map_x3d(x); /* Normalize object space to -1..1 */
v[1] = map_y3d(y);
v[2] = map_z3d(z);
v[3] = 1.0;
res = trans_mat[3][2]; /* Initiate it with the weight factor. */
for (i = 0; i < 3; i++) res += v[i] * trans_mat[i][2];
if(w==0) w= 1e-5;
for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
zt = ((int) (res * 16384 / w));
return zt;
}
/* borders of plotting area */
/* computed once on every call to do_plot */
static void boundary3d(scaling,plots,count)
TBOOLEAN scaling; /* TRUE if terminal is doing the scaling */
struct surface_points *plots;
int count;
{
register struct termentry *t = term;
int ytlen, i;
titlelin = 0;
p_height= pointsize * t->v_tic;
p_width = pointsize * t->h_tic;
key_entry_height = pointsize * (t->v_tic) * 1.25;
if (key_entry_height < (t->v_char) )
key_entry_height = (t->v_char);
/* count max_len key and number keys (plot-titles and contour labels) with len > 0 */
max_ptitl_len = find_maxl_keys3d(plots,count,&ptitl_cnt);
if ( (ytlen = label_width(key_title,&ktitle_lines)) > max_ptitl_len )
max_ptitl_len = ytlen;
key_col_wth = (max_ptitl_len + 4 ) * (t->h_char) + KEYWTH;
/* luecken@udel.edu modifications
sizes the plot to take up more of available resolution */
if ( lmargin >= 0 )
xleft = (t->h_char)*lmargin;
else
xleft = (t->h_char)*2 + (t->h_tic);
xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
key_rows = ptitl_cnt;
key_cols = 1;
if (key == -1 && key_vpos == TUNDER ) {
/* calculate max no cols, limited by label-length */
key_cols = (int)(xright - xleft)/((max_ptitl_len + 4 ) * (t->h_char) + KEYWTH);
key_rows = (int)(ptitl_cnt/key_cols)+((ptitl_cnt%key_cols)>0);
/* now calculate actual no cols depending on no rows */
key_cols = (int)(ptitl_cnt/key_rows)+((ptitl_cnt%key_rows)>0);
key_col_wth = (int)(xright - xleft)/key_cols;
/* key_rows += ktitle_lines; - messes up key - div */
}
/* this should also consider the view and number of lines in xformat || yformat || xlabel || ylabel */
ybot = (t->v_char)*2.5 + 1; /* an absolute 1, with no terminal-dependent scaling ? */
if (key_rows&&key_vpos==TUNDER)
ybot += key_rows*key_entry_height + ktitle_lines*t->v_char;
if (strlen(title.text)) {
titlelin++;
for(i=0;i<strlen(title.text);i++) {
if (title.text[i] == '\\') titlelin++;
}
}
ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*(titlelin+1.5) - 1;
if (key == -1 && key_vpos != TUNDER ) {
/* calculate max no rows, limited be ytop-ybot */
i = (int)(ytop-ybot)/(t->v_char) - 1 - ktitle_lines;
if (ptitl_cnt > i) {
key_cols = (int)(ptitl_cnt/i)+((ptitl_cnt%i)>0);
/* now calculate actual no rows depending on no cols */
key_rows = (int)(ptitl_cnt/key_cols)+((ptitl_cnt%key_cols)>0);
}
key_rows += ktitle_lines;
}
if ( key_hpos == TOUT ) {
xright -= key_col_wth*(key_cols-1) + key_col_wth - 2*(t->h_char);
}
xleft += t->xmax * xoffset;
xright += t->xmax * xoffset;
ytop += t->ymax * yoffset;
ybot += t->ymax * yoffset;
xmiddle = (xright + xleft) / 2;
ymiddle = (ytop + ybot) / 2;
xscaler = (xright - xleft) * 4 / 7;
yscaler = (ytop - ybot) * 4 / 7;
}
#if 0
/* not used ; anyway, should be done using bitshifts and squares,
* rather than iteratively
*/
static double dbl_raise(x,y)
double x;
int y;
{
register int i=ABS(y);
double val=1.0;
while (--i >= 0)
val *= x;
if (y < 0 ) return (1.0/val);
return(val);
}
#endif
/* we precalculate features of the key, to save lots of nested
* ifs in code - x,y = user supplied or computed position of key
* taken to be inner edge of a line sample
*/
static int key_sample_left; /* offset from x for left of line sample */
static int key_sample_right; /* offset from x for right of line sample */
static int key_point_offset; /* offset from x for point sample */
static int key_text_left; /* offset from x for left-justified text */
static int key_text_right; /* offset from x for right-justified text */
static int key_size_left; /* distance from x to left edge of box */
static int key_size_right; /* distance from x to right edge of box */
void do_3dplot(plots, pcount)
struct surface_points *plots;
int pcount; /* count of plots in linked list */
{
struct termentry *t = term;
int surface;
struct surface_points *this_plot = NULL;
unsigned int xl, yl;
int linetypeOffset = 0;
double ztemp, temp;
struct text_label *this_label;
struct arrow_def *this_arrow;
TBOOLEAN scaling;
transform_matrix mat;
int key_count;
char ss[MAX_LINE_LEN+1], *s, *e;
/* Initiate transformation matrix using the global view variables. */
mat_rot_z(surface_rot_z, trans_mat);
mat_rot_x(surface_rot_x, mat);
mat_mult(trans_mat, trans_mat, mat);
mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
mat_mult(trans_mat, trans_mat, mat);
/* modify min_z/max_z so it will zscale properly. */
ztemp = (z_max3d - z_min3d) / (2.0 * surface_zscale);
temp = (z_max3d + z_min3d) / 2.0;
z_min3d = temp - ztemp;
z_max3d = temp + ztemp;
#if 0 /* already done in eval_3dplots */
/* auto-extend ranges to tic-mark for autoscaled axes */
if (xtics) setup_tics(FIRST_X_AXIS, &xticdef, xformat);
if (ytics) setup_tics(FIRST_Y_AXIS, &yticdef, yformat);
if (ztics) setup_tics(FIRST_Z_AXIS, &zticdef, zformat);
#endif
/* The extrema need to be set even when a surface is not being
* drawn. Without this, gnuplot used to assume that the X and
* Y axis started at zero. -RKC
*/
if (polar)
graph_error("Cannot splot in polar coordinate system.");
/* done in plot3d.c
* if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
* x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
* y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
* graph_error("all points undefined!");
*/
/* If we are to draw the bottom grid make sure zmin is updated properly. */
if (xtics || ytics || grid) {
base_z = z_min3d - (z_max3d - z_min3d) * ticslevel;
if (ticslevel >= 0)
floor_z = base_z;
else
floor_z = z_min3d;
if (ticslevel < -1)
ceiling_z = base_z;
else
ceiling_z = z_max3d;
} else {
floor_z = base_z = z_min3d;
ceiling_z = z_max3d;
}
/* This used be x_max3d == x_min3d, but that caused an infinite loop once. */
if (fabs(x_max3d - x_min3d) < zero)
graph_error("x_min3d should not equal x_max3d!");
if (fabs(y_max3d - y_min3d) < zero)
graph_error("y_min3d should not equal y_max3d!");
if (fabs(z_max3d - z_min3d) < zero)
graph_error("z_min3d should not equal z_max3d!");
#ifndef LITE
if (hidden3d) {
struct surface_points *plot;
int p=0;
/* Verify data is hidden line removable - grid based. */
for (plot = plots; ++p <= pcount; plot = plot->next_sp) {
if (plot->plot_type == DATA3D && !plot->has_grid_topology){
fprintf(stderr,"Notice: Cannot remove hidden lines from non grid data\n");
return;
}
}
}
#endif /* not LITE */
/* INITIALIZE TERMINAL */
if (!term_init) {
(*t->init)();
term_init = TRUE;
}
screen_ok = FALSE;
scaling = (*t->scale)(xsize, ysize);
if (multiplot && term_graphics) {
if (term_suspended && term->resume)
(*t->resume)();
term_suspended = FALSE;
} else {
(*t->graphics)();
term_graphics = TRUE;
}
/* now compute boundary for plot (xleft, xright, ytop, ybot) */
boundary3d(scaling,plots,pcount);
/* SCALE FACTORS */
zscale3d = 2.0/(ceiling_z - floor_z);
yscale3d = 2.0/(y_max3d - y_min3d);
xscale3d = 2.0/(x_max3d - x_min3d);
(*t->linetype)(-2); /* border linetype */
/* PLACE TITLE */
if (*title.text != 0) {
strcpy(ss, title.text);
write_multiline( (unsigned int)((xleft+xright)/2+title.xoffset*t->h_char),
(unsigned int)(ytop+(titlelin+title.yoffset)*(t->h_char)),
ss, CENTRE, JUST_TOP, 0, title.font);
}
/* PLACE TIMEDATE */
if (*timelabel.text) {
char str[MAX_LINE_LEN+1];
time_t now;
unsigned int x = t->v_char + timelabel.xoffset * t->h_char;
unsigned int y = yoffset*ymax + (timelabel.yoffset+1) * t->v_char;
time(&now);
strftime(str, MAX_LINE_LEN, timelabel.text, localtime(&now));
if ((*t->text_angle)(1)) {
write_multiline(x,y,str,CENTRE, JUST_TOP, 1, timelabel.font);
(*t->text_angle)(0);
} else {
write_multiline(x,y,str,LEFT, JUST_BOT, 0, timelabel.font);
}
}
/* PLACE LABELS */
for (this_label = first_label; this_label!=NULL;
this_label=this_label->next ) {
unsigned int x,y;
map_position(&this_label->place, &x, &y, "label");
strcpy(ss, this_label->text);
write_multiline( x,y, this_label->text, this_label->pos, CENTRE, 0, this_label->font);
}
/* PLACE ARROWS */
for (this_arrow = first_arrow; this_arrow!=NULL;
this_arrow = this_arrow->next ) {
unsigned int sx,sy,ex,ey;
map_position(&this_arrow->start, &sx, &sy, "arrow");
map_position(&this_arrow->end, &ex, &ey, "arrow");
(*t->linetype)(this_arrow->line);
(*t->arrow)(sx, sy, ex, ey, this_arrow->head);
}
#ifndef LITE
if (hidden3d && draw_surface) {
init_hidden_line_removal();
reset_hidden_line_removal();
hidden_active = TRUE;
}
#endif /* not LITE */
/* WORK OUT KEY SETTINGS AND DO KEY TITLE / BOX */
if (key_reverse) {
key_sample_left= -KEYWTH;
key_sample_right= 0;
key_text_left=t->h_char;
key_text_right=(t->h_char)*(max_ptitl_len+1);
key_size_right=(t->h_char)*(max_ptitl_len+2);
key_size_left=(t->h_char) + KEYWTH;
} else {
key_sample_left= 0;
key_sample_right= KEYWTH;
key_text_left=-(t->h_char)*(max_ptitl_len+1);
key_text_right=-(t->h_char);
key_size_left=(t->h_char)*(max_ptitl_len+2);
key_size_right=(t->h_char)+KEYWTH;
}
key_point_offset = (key_sample_left + key_sample_right)/2;
if (key == -1) {
if ( key_vpos == TUNDER ) {
#if 0
yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines+2)*t->v_char;
xl = max_ptitl_len * 1000/( KEYWTH/(t->h_char) + max_ptitl_len + 2);
xl *= (xright - xleft)/key_cols;
xl /= 1000;
xl += xleft;
#else
/* maximise no cols, limited by label-length */
key_cols = (int)(xright - xleft)/key_col_wth;
key_rows = (int)(ptitl_cnt+key_cols-1)/key_cols;
/* now calculate actual no cols depending on no rows */
key_cols = (int)(ptitl_cnt+key_rows-1)/key_rows;
key_col_wth = (int)(xright - xleft)/key_cols;
/* we divide into columns, then centre in column by considering ratio
* of key_left_size to key_right_size
* key_size_left/(key_size_left+key_size_right) * (xright-xleft)/key_cols
* do one integer division to maximise accuracy (hope we dont overflow !)
*/
xl = xleft + ((xright-xleft)*key_size_left) / (key_cols*(key_size_left+key_size_right));
yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines+2)*t->v_char;
#endif
} else {
if ( key_vpos == TTOP ) {
yl = ytop - (t->v_tic) - t->v_char;
} else {
yl = ybot + (t->v_tic) + key_entry_height*key_rows + ktitle_lines*t->v_char;
}
if ( key_hpos == TOUT ) {
/* keys outside plot border (right) */
xl = xright + (t->h_tic) + key_size_left;
} else if ( key_hpos == TLEFT ) {
xl = xleft + (t->h_tic) + key_size_left;
} else {
xl = xright - key_size_right - key_col_wth*(key_cols-1);
}
}
yl_ref = yl - ktitle_lines * (t->v_char);
}
if (key == 1) {
map_position(&key_user_pos, &xl, &yl, "key");
}
if (key && key_box>-3) {
int yt=yl;
int yb=yl - key_entry_height*(key_rows-ktitle_lines) - ktitle_lines*t->v_char;
int key_xr = xl + key_col_wth * (key_cols-1) + key_size_right;
/* key_rows seems to contain title at this point ??? */
(*t->linetype)(key_box);
(*t->move)(xl-key_size_left,yb);
(*t->vector)(xl-key_size_left,yt);
(*t->vector)(key_xr,yt);
(*t->vector)(key_xr,yb);
(*t->vector)(xl-key_size_left,yb);
/* draw a horizontal line between key title and first entry */ /* JFi */
(*t->move)(xl-key_size_left,yt - (ktitle_lines) * t->v_char); /* JFi */
(*t->vector)(xl+key_size_right,yt - (ktitle_lines) * t->v_char); /* JFi */
}
/* DRAW SURFACES AND CONTOURS */
#ifndef LITE
if (hidden3d && draw_surface) plot3d_hidden(plots,pcount);
#endif /* not LITE */
if (key != 0 && strlen(key_title)) {
sprintf(ss,"%s\n",key_title);
s = ss;
yl -= t->v_char/2;
while( (e=(char *)strchr(s,'\n')) != NULL ) {
*e = '\0';
if ( key_just == JLEFT) {
(*t->justify_text)(LEFT);
(*t->put_text)(xl+key_text_left,yl,s);
} else {
if ((*t->justify_text)(RIGHT)) {
(*t->put_text)(xl+key_text_right,
yl,s);
} else {
int x=xl+key_text_right-(t->h_char)*strlen(s);
if (inrange(x,xleft, xright))
(*t->put_text)(x,yl,s);
}
}
s = ++e;
yl -= t->v_char;
}
yl += t->v_char/2;
}
key_count = 0;
yl_ref = yl -= key_entry_height/2; /* centralise the keys */
this_plot = plots;
for (surface = 0;
surface < pcount;
this_plot = this_plot->next_sp, surface++) {
#ifndef LITE
if ( hidden3d )
hidden_no_update = FALSE;
#endif /* not LITE */
if (draw_surface) {
(*t->linetype)(this_plot->line_type);
#ifndef LITE
if (hidden3d) {
hidden_line_type_above = this_plot->line_type;
hidden_line_type_below = this_plot->line_type + 1;
}
#endif /* not LITE */
if (key != 0 && this_plot->title) {
key_count++;
key_text(xl, yl, this_plot->title);
}
switch(this_plot->plot_style) {
case BOXES: /* can't do boxes in 3d yet so use impulses */
case IMPULSES: {
if (key != 0 && this_plot->title) {
key_sample_line(xl,yl);
}
if (!(hidden3d && draw_surface))
plot3d_impulses(this_plot);
break;
}
case LINES: {
if (key != 0 && this_plot->title) {
key_sample_line(xl,yl);
}
if (!(hidden3d && draw_surface))
plot3d_lines(this_plot);
break;
}
case YERRORBARS: /* ignored; treat like points */
case XERRORBARS: /* ignored; treat like points */
case XYERRORBARS: /* ignored; treat like points */
case POINTSTYLE: {
if (key != 0 && this_plot->title
&& !clip_point(xl+key_point_offset,yl)) {
key_sample_point(xl,yl,this_plot->point_type);
}
if (!(hidden3d && draw_surface))
plot3d_points(this_plot);
break;
}
case LINESPOINTS: {
/* put lines */
if (key != 0 && this_plot->title) {
key_sample_line(xl,yl);
}
if (!(hidden3d && draw_surface))
plot3d_lines(this_plot);
/* put points */
if (key != 0 && this_plot->title
&& !clip_point(xl+key_point_offset,yl)) {
(*t->point)(xl+key_point_offset,yl,
this_plot->point_type);
}
if (!(hidden3d && draw_surface))
plot3d_points(this_plot);
break;
}
case DOTS: {
if (key != 0 && this_plot->title) {
if (key == 1) {
if (!clip_point(xl+key_point_offset,yl))
(*t->point)(xl+key_point_offset,yl, -1);
} else {
(*t->point)(xl+key_point_offset,yl, -1);
/* (*t->point)(xl+2*(t->h_char),yl, -1); */
}
}
if (!(hidden3d && draw_surface))
plot3d_dots(this_plot);
break;
}
}
if (key != 0 && this_plot->title) {
if ( key_count >= key_rows ) {
yl = yl_ref;
xl += key_col_wth;
key_count = 0;
} else
yl -= key_entry_height;
}
}
#ifndef LITE
if ( hidden3d ) {
hidden_no_update = TRUE;
hidden_line_type_above = this_plot->line_type + (hidden3d ? 2 : 1);
hidden_line_type_below = this_plot->line_type + (hidden3d ? 2 : 1);
}
#endif /* not LITE */
if (draw_contour && this_plot->contours != NULL) {
struct gnuplot_contours *cntrs = this_plot->contours;
(*t->linetype)(this_plot->line_type + (hidden3d ? 2 : 1));
if (key != 0 && this_plot->title
&& !draw_surface && !label_contours) {
key_count++;
key_text(xl,yl, this_plot->title);
switch(this_plot->plot_style) {
case IMPULSES:
case LINES:
key_sample_line(xl,yl);
break;
case YERRORBARS: /* ignored; treat like points */
case XERRORBARS: /* ignored; treat like points */
case XYERRORBARS: /* ignored; treat like points */
case POINTSTYLE:
key_sample_point(xl,yl,this_plot->point_type);
break;
case LINESPOINTS:
key_sample_line(xl,yl);
break;
case DOTS:
key_sample_point(xl,yl,-1);
break;
}
}
linetypeOffset = this_plot->line_type + (hidden3d ? 2 : 1);
while (cntrs) {
if(label_contours && cntrs->isNewLevel) {
(*t->linetype)(linetypeOffset++);
if (key) {
#ifndef LITE
if(hidden3d) hidden_line_type_below = hidden_line_type_above = linetypeOffset-1;
#endif /* not LITE */
key_count++;
key_text(xl,yl,cntrs->label);
switch(this_plot->plot_style) {
case IMPULSES:
case LINES:
case LINESPOINTS:
key_sample_line(xl,yl);
break;
case YERRORBARS: /* ignored; treat like points */
case XERRORBARS: /* ignored; treat like points */
case XYERRORBARS: /* ignored; treat like points */
case POINTSTYLE:
key_sample_point(xl,yl,this_plot->point_type);
break;
case DOTS:
key_sample_point(xl,yl,-1);
break;
} /* switch */
if (key_count >= key_rows ) {
yl = yl_ref;
xl += key_col_wth;
key_count = 0;
} else /* might want to use t->v_char if not putting points in key - div */
yl -= key_entry_height;
} /* key */
} /* label_contours */
switch(this_plot->plot_style) {
case IMPULSES:
cntr3d_impulses(cntrs, this_plot);
break;
case LINES:
cntr3d_lines(cntrs);
break;
case YERRORBARS: /* ignored; treat like points */
case XERRORBARS: /* ignored; treat like points */
case XYERRORBARS: /* ignored; treat like points */
case POINTSTYLE:
cntr3d_points(cntrs, this_plot);
break;
case LINESPOINTS:
cntr3d_lines(cntrs);
cntr3d_points(cntrs, this_plot);
break;
case DOTS:
cntr3d_dots(cntrs);
break;
}
cntrs = cntrs->next;
}
if (key != 0 && this_plot->title) {
if (key_count >= key_rows ) {
yl = yl_ref;
xl += key_col_wth;
key_count = 0;
} else
yl -= key_entry_height;
}
}
}
draw_bottom_grid(plots, pcount);
if (!multiplot) {
(*t->text)();
term_graphics = FALSE;
}
(void) fflush(outfile);
#ifndef LITE
if (hidden3d && draw_surface) {
term_hidden_line_removal();
hidden_active = FALSE;
}
#endif /* not LITE */
}
/* plot3d_impulses:
* Plot the surfaces in IMPULSES style
*/
static void plot3d_impulses(plot)
struct surface_points *plot;
{
int i; /* point index */
unsigned int x,y,x0,y0; /* point in terminal coordinates */
struct iso_curve *icrvs = plot->iso_crvs;
while ( icrvs ) {
struct coordinate GPHUGE *points = icrvs->points;
for (i = 0; i < icrvs->p_count; i++) {
switch (points[i].type)
{
case INRANGE:
{
map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
if(inrange(0.0, min3d_z, max3d_z)){
map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
} else if(inrange(min3d_z, 0.0, points[i].z)){
map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
} else {
map3d_xy(points[i].x, points[i].y, max3d_z, &x0, &y0);
}
clip_move(x0,y0);
clip_vector(x,y);
break;
}
case OUTRANGE:
{
if(!inrange(points[i].x, x_min3d, x_max3d) ||
!inrange(points[i].y, y_min3d, y_max3d))
break;
if(inrange(0.0, min3d_z, max3d_z))
{
/* zero point is INRANGE */
map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
/* must cross z=min3d_z or max3d_z limits */
if(inrange(min3d_z, 0.0, points[i].z) &&
min3d_z != 0.0 && min3d_z != points[i].z)
{
map3d_xy(points[i].x, points[i].y, min3d_z, &x, &y);
}
else
{
map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
}
}
else
{
/* zero point is also OUTRANGE */
if(inrange(min3d_z, 0.0, points[i].z) &&
inrange(max3d_z, 0.0, points[i].z))
{
/* crosses z=min3d_z or max3d_z limits */
map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
}
else
{
/* doesn't cross z=min3d_z or max3d_z limits */
break;
}
}
clip_move(x0,y0);
clip_vector(x,y);
break;
}
default: /* just a safety */
case UNDEFINED: {
break;
}
}
}
icrvs = icrvs->next;
}
}
/* plot3d_lines:
* Plot the surfaces in LINES style
*/
/* We want to always draw the lines in the same direction, otherwise when
we draw an adjacent box we might get the line drawn a little differently
and we get splotches. */
#ifndef LITE
#endif /* not LITE */
static void plot3d_lines(plot)
struct surface_points *plot;
{
int i;
unsigned int x,y,x0,y0; /* point in terminal coordinates */
double clip_x, clip_y, clip_z;
struct iso_curve *icrvs = plot->iso_crvs;
struct coordinate GPHUGE *points;
enum coord_type prev = UNDEFINED;
double lx[2], ly[2], lz[2]; /* two edge points */
#ifndef LITE
/* These are handled elsewhere. */
if (plot->has_grid_topology && hidden3d)
return;
#endif /* not LITE */
while (icrvs) {
prev = UNDEFINED; /* type of previous plot */
for(i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
switch (points[i].type) {
case INRANGE: {
map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
if(prev == INRANGE)
{
clip_vector(x, y);
}
else
{
if(prev == OUTRANGE)
{
/* from outrange to inrange */
if (!clip_lines1) {
clip_move(x, y);
}
else {
/*
* Calculate intersection point and draw vector from there
*/
edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
clip_move(x0,y0);
clip_vector(x,y);
}
}
else
{
clip_move(x,y);
}
}
break;
}
case OUTRANGE:{
if(prev == INRANGE)
{
/* from inrange to outrange */
if (clip_lines1) {
/*
* Calculate intersection point and draw vector to it
*/
edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
clip_vector(x0,y0);
}
}
else if (prev == OUTRANGE)
{
/* from outrange to outrange */
if (clip_lines2) {
/*
* Calculate the two 3D intersection points if present
*/
if (two_edge3d_intersect(points, i, lx, ly, lz)) {
map3d_xy(lx[0], ly[0], lz[0], &x, &y);
map3d_xy(lx[1], ly[1], lz[1], &x0, &y0);
clip_move(x, y);
clip_vector(x0, y0);
}
}
}
break;
}
case UNDEFINED: {
break;
default: graph_error("Unknown point type in plot3d_lines");
}
}
prev = points[i].type;
}
icrvs = icrvs->next;
}
}
/* plot3d_points:
* Plot the surfaces in POINTSTYLE style
*/
static void plot3d_points(plot)
struct surface_points *plot;
{
int i;
unsigned x,y;
struct termentry *t = term;
struct iso_curve *icrvs = plot->iso_crvs;
while ( icrvs ) {
struct coordinate GPHUGE *points = icrvs->points;
for (i = 0; i < icrvs->p_count; i++) {
if (points[i].type == INRANGE) {
map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
if (!clip_point(x,y))
(*t->point)(x,y, plot->point_type);
}
}
icrvs = icrvs->next;
}
}
/* plot3d_dots:
* Plot the surfaces in DOTS style
*/
static void plot3d_dots(plot)
struct surface_points *plot;
{
int i;
struct termentry *t = term;
struct iso_curve *icrvs = plot->iso_crvs;
while ( icrvs ) {
struct coordinate GPHUGE *points = icrvs->points;
for (i = 0; i < icrvs->p_count; i++) {
unsigned int x,y;
map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
if (!clip_point(x,y))
(*t->point)(x,y, -1);
}
icrvs = icrvs->next;
}
}
/* cntr3d_impulses:
* Plot a surface contour in IMPULSES style
*/
static void cntr3d_impulses(cntr, plot)
struct gnuplot_contours *cntr;
struct surface_points *plot;
{
int i; /* point index */
unsigned int x,y,x0,y0; /* point in terminal coordinates */
if (draw_contour & CONTOUR_SRF) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
&x, &y);
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
&x0, &y0);
clip_move(x0,y0);
clip_vector(x,y);
}
}
else
cntr3d_points(cntr, plot); /* Must be on base grid, so do points. */
}
/* cntr3d_lines:
* Plot a surface contour in LINES style
*/
static void cntr3d_lines(cntr)
struct gnuplot_contours *cntr;
{
int i; /* point index */
unsigned int x,y; /* point in terminal coordinates */
if (draw_contour & CONTOUR_SRF) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
&x, &y);
if (i > 0) {
clip_vector(x,y);
if(i == 1) suppressMove = TRUE;
} else {
clip_move(x,y);
}
}
}
suppressMove = FALSE; /* beginning a new contour level, so moveto() required */
if (draw_contour & CONTOUR_BASE) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
&x, &y);
if (i > 0) {
clip_vector(x,y);
if(i == 1) suppressMove = TRUE;
} else {
clip_move(x,y);
}
}
}
suppressMove = FALSE; /* beginning a new contour level, so moveto() required */
}
/* cntr3d_points:
* Plot a surface contour in POINTSTYLE style
*/
static void cntr3d_points(cntr, plot)
struct gnuplot_contours *cntr;
struct surface_points *plot;
{
int i;
unsigned int x,y;
struct termentry *t = term;
if (draw_contour & CONTOUR_SRF) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
&x, &y);
if (!clip_point(x,y))
(*t->point)(x,y, plot->point_type);
}
}
if (draw_contour & CONTOUR_BASE) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
&x, &y);
if (!clip_point(x,y))
(*t->point)(x,y, plot->point_type);
}
}
}
/* cntr3d_dots:
* Plot a surface contour in DOTS style
*/
static void cntr3d_dots(cntr)
struct gnuplot_contours *cntr;
{
int i;
unsigned int x,y;
struct termentry *t = term;
if (draw_contour & CONTOUR_SRF) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
&x, &y);
if (!clip_point(x,y))
(*t->point)(x,y, -1);
}
}
if (draw_contour & CONTOUR_BASE) {
for (i = 0; i < cntr->num_pts; i++) {
map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
&x, &y);
if (!clip_point(x,y))
(*t->point)(x,y, -1);
}
}
}
/* map xmin | xmax to 0 | 1 and same for y
* 0.1 avoids any rounding errors
*/
#define MAP_HEIGHT_X(x) ( (int) (((x)-x_min3d)/(x_max3d-x_min3d)+0.1) )
#define MAP_HEIGHT_Y(y) ( (int) (((y)-y_min3d)/(y_max3d-y_min3d)+0.1) )
/* if point is at corner, update height[][] and depth[][]
* we are still assuming that extremes of surfaces are at corners,
* but we are not assuming order of corners
*/
static void check_corner_height(p,height,depth)
struct coordinate GPHUGE *p;
double height[2][2];
double depth[2][2];
{
if (p->type != INRANGE) return;
if ( (fabs(p->x - x_min3d)<zero || fabs(p->x - x_max3d)<zero) &&
(fabs(p->y - y_min3d)<zero || fabs(p->y - y_max3d)<zero)) {
unsigned int x= MAP_HEIGHT_X(p->x);
unsigned int y= MAP_HEIGHT_Y(p->y);
if (height[x][y] < p->z)
height[x][y] = p->z;
if (depth[x][y] > p->z)
depth[x][y] = p->z;
}
}
/* Draw the bottom grid that hold the tic marks for 3d surface. */
static void draw_bottom_grid(plot, plot_num)
struct surface_points *plot;
int plot_num;
{
unsigned int x,y; /* point in terminal coordinates */
struct termentry *t = term;
char ss[MAX_LINE_LEN+1];
/* work out where the axes and tics are drawn */
{
int quadrant=surface_rot_z/90;
if ( (quadrant+1)&2) {
zaxis_x = x_max3d;
xaxis_y = y_max3d;
} else {
zaxis_x = x_min3d;
xaxis_y = y_min3d;
}
if (quadrant&2) {
zaxis_y = y_max3d;
yaxis_x = x_min3d;
} else {
zaxis_y = y_min3d;
yaxis_x = x_max3d;
}
if (surface_rot_x > 90) {
/* labels on the back axes */
back_x = yaxis_x = x_min3d + x_max3d - yaxis_x;
back_y = xaxis_y = y_min3d + y_max3d - xaxis_y;
} else {
back_x = x_min3d + x_max3d - yaxis_x;
back_y = y_min3d + y_max3d - xaxis_y;
}
}
if (draw_border) {
unsigned int bl_x, bl_y; /* bottom left */
unsigned int bb_x, bb_y; /* bottom back */
unsigned int br_x, br_y; /* bottom right */
unsigned int bf_x, bf_y; /* bottom front */
#ifndef LITE
int save_update=hidden_no_update;
hidden_no_update=TRUE;
#endif /* LITE */
setlinestyle(-2);
map3d_xy(zaxis_x, zaxis_y, base_z, &bl_x, &bl_y);
map3d_xy( back_x, back_y, base_z, &bb_x, &bb_y);
map3d_xy(x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, base_z, &br_x, &br_y);
map3d_xy(x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, base_z, &bf_x, &bf_y);
/* border around base */
{
int save=hidden_active;
hidden_active=FALSE; /* this is in front */
if (draw_border&4) draw_clip_line(br_x, br_y, bf_x, bf_y);
if (draw_border&1) draw_clip_line(bl_x, bl_y, bf_x, bf_y);
hidden_active=save;
}
if (draw_border&2) draw_clip_line(bl_x, bl_y, bb_x, bb_y);
if (draw_border&8) draw_clip_line(br_x, br_y, bb_x, bb_y);
if ( draw_surface || (draw_contour&CONTOUR_SRF)) {
int save=hidden_active;
/* map the 8 corners to screen */
unsigned int fl_x, fl_y; /* floor left */
unsigned int fb_x, fb_y; /* floor back */
unsigned int fr_x, fr_y; /* floor right */
unsigned int ff_x, ff_y; /* floor front */
unsigned int tl_x, tl_y; /* top left */
unsigned int tb_x, tb_y; /* top back */
unsigned int tr_x, tr_y; /* top right */
unsigned int tf_x, tf_y; /* top front */
map3d_xy(zaxis_x, zaxis_y, floor_z, &fl_x, &fl_y);
map3d_xy( back_x, back_y, floor_z, &fb_x, &fb_y);
map3d_xy(x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, floor_z, &fr_x, &fr_y);
map3d_xy(x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, floor_z, &ff_x, &ff_y);
map3d_xy(zaxis_x, zaxis_y, ceiling_z, &tl_x, &tl_y);
map3d_xy( back_x, back_y, ceiling_z, &tb_x, &tb_y);
map3d_xy(x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, ceiling_z, &tr_x, &tr_y);
map3d_xy(x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, ceiling_z, &tf_x, &tf_y);
/* vertical lines, to surface or to very top */
if ( (draw_border & 0xf0)==0xf0) {
/* all four verticals drawn - save some time */
draw_clip_line(fl_x, fl_y, tl_x, tl_y);
draw_clip_line(fb_x, fb_y, tb_x, tb_y);
draw_clip_line(fr_x, fr_y, tr_x, tr_y);
hidden_active=FALSE; /* this is in front */
draw_clip_line(ff_x, ff_y, tf_x, tf_y);
hidden_active=save;
} else {
/* search surfaces for heights at corners */
double height[2][2];
double depth[2][2];
unsigned int zaxis_i=MAP_HEIGHT_X(zaxis_x);
unsigned int zaxis_j=MAP_HEIGHT_Y(zaxis_y);
unsigned int back_i=MAP_HEIGHT_X(back_x);
int back_j=MAP_HEIGHT_Y(back_y);
height[0][0]=height[0][1]=height[1][0]=height[1][1]=base_z;
depth[0][0]=depth[0][1]=depth[1][0]=depth[1][1]=base_z;
for (; --plot_num >= 0; plot=plot->next_sp) {
struct iso_curve *curve=plot->iso_crvs;
int count=curve->p_count;
int iso;
if (plot->plot_type==DATA3D) {
if (!plot->has_grid_topology) continue;
iso=plot->num_iso_read;
} else
iso=iso_samples_2;
check_corner_height(curve->points, height, depth);
check_corner_height(curve->points+count-1, height, depth);
while (--iso)
curve=curve->next;
check_corner_height(curve->points, height, depth);
check_corner_height(curve->points+count-1, height, depth);
}
#define VERTICAL(mask, x,y,i,j,bx,by,tx,ty) \
if (draw_border&mask) \
draw_clip_line(bx,by,tx,ty);\
else if (height[i][j]!=depth[i][j]) \
{ unsigned int a0,b0, a1, b1; \
map3d_xy(x,y,depth[i][j],&a0,&b0); \
map3d_xy(x,y,height[i][j],&a1,&b1); \
draw_clip_line(a0,b0,a1,b1); \
}
VERTICAL(16, zaxis_x, zaxis_y, zaxis_i, zaxis_j,fl_x, fl_y, tl_x, tl_y)
VERTICAL(32, back_x, back_y, back_i, back_j,fb_x, fb_y, tb_x, tb_y)
VERTICAL(64, x_min3d+x_max3d-zaxis_x, y_min3d+y_max3d-zaxis_y, 1-zaxis_i, 1-zaxis_j,fr_x, fr_y, tr_x, tr_y)
hidden_active=FALSE;
VERTICAL(128, x_min3d+x_max3d-back_x, y_min3d+y_max3d-back_y, 1-back_i, 1-back_j,ff_x, ff_y, tf_x, tf_y)
hidden_active=save;
}
/* now border lines on top */
if (draw_border&256) draw_clip_line(tl_x, tl_y, tb_x, tb_y);
if (draw_border&512) draw_clip_line(tr_x, tr_y, tb_x, tb_y);
/* these lines are in front of surface (?) */
hidden_active=FALSE;
if (draw_border&1024) draw_clip_line(tl_x, tl_y, tf_x, tf_y);
if (draw_border&2048) draw_clip_line(tr_x, tr_y, tf_x, tf_y);
hidden_active=save;
}
#ifndef LITE
hidden_no_update=save_update;
#endif /* LITE */
}
if (xtics || *xlabel.text) {
unsigned int x0,y0,x1,y1;
double mid_x = (x_max3d+x_min3d)/2;
double len;
map3d_xy(mid_x, xaxis_y, base_z, &x0, &y0);
map3d_xy(mid_x, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
{ /* take care over unsigned quantities */
int dx = x1-x0;
int dy = y1-y0;
len=sqrt((double)(dx*dx+dy*dy));
tic_unitx = dx/len;
tic_unity = dy/len;
}
if (xtics) {
gen_tics(FIRST_X_AXIS, &xticdef,grid&(GRID_X|GRID_MX),mxtics,mxtfreq, xtick_callback);
}
if (*xlabel.text) {
/* label at xaxis_y + 1/4 of (xaxis_y-other_y) */
double step = (2*xaxis_y-y_max3d-y_min3d)/4;
map3d_xy(mid_x, xaxis_y+step, base_z,&x1,&y1);
x1 += xlabel.xoffset * t->h_char;
y1 += xlabel.yoffset * t->v_char;
if (!tic_in) {
x1 -= tic_unitx*ticscale*(t->h_tic);
y1 -= tic_unity*ticscale*(t->v_tic);
}
strcpy(ss, xlabel.text); /* write_multiline mods it */
write_multiline(x1,y1,ss, CENTRE, JUST_TOP,0, xlabel.font);
}
}
if (ytics || *ylabel.text) {
unsigned int x0,y0,x1,y1;
double mid_y = (y_max3d+y_min3d)/2;
double len;
map3d_xy(yaxis_x, mid_y, base_z, &x0, &y0);
map3d_xy(x_min3d + x_max3d - yaxis_x, mid_y, base_z, &x1, &y1);
{ /* take care over unsigned quantities */
int dx = x1-x0;
int dy = y1-y0;
len=sqrt((double)(dx*dx+dy*dy));
tic_unitx = dx/len;
tic_unity = dy/len;
}
if (ytics) {
gen_tics(FIRST_Y_AXIS, &yticdef,grid&(GRID_Y|GRID_MY),mytics,mytfreq, ytick_callback);
}
if (*ylabel.text) {
double step = (x_max3d+x_min3d-2*yaxis_x)/4;
map3d_xy(yaxis_x-step, mid_y, base_z,&x1,&y1);
x1 += ylabel.xoffset * t->h_char;
y1 += ylabel.yoffset * t->v_char;
if (!tic_in) {
x1 -= tic_unitx*ticscale*(t->h_tic);
y1 -= tic_unity*ticscale*(t->v_tic);
}
strcpy(ss, ylabel.text); /* write_multiline mods it */
write_multiline(x1,y1,ss, CENTRE, JUST_TOP,0, ylabel.font);
}
}
/* do z tics */
if (ztics && (draw_surface || (draw_contour&CONTOUR_SRF))) {
gen_tics(FIRST_Z_AXIS, &zticdef, grid&(GRID_Z|GRID_MZ), mztics, mztfreq, ztick_callback);
}
if ( (xzeroaxis>=-2) && !is_log_y && inrange(0,y_min3d, y_max3d)) {
unsigned int x,y,x1,y1;
(*t->linetype)(xzeroaxis);
map3d_xy(x_min3d, 0.0, base_z, &x, &y);
map3d_xy(x_max3d, 0.0, base_z, &x1, &y1);
draw_clip_line(x,y,x1,y1);
}
if ((yzeroaxis>=-2) && !is_log_x && inrange(0,x_min3d, x_max3d)) {
unsigned int x,y,x1,y1;
(*t->linetype)(yzeroaxis);
map3d_xy(0.0, y_min3d, base_z, &x, &y);
map3d_xy(0.0, y_max3d, base_z, &x1, &y1);
draw_clip_line(x,y,x1,y1);
}
/* PLACE ZLABEL - along the middle grid Z axis - eh ? */
if (*zlabel.text && (draw_surface || (draw_contour & CONTOUR_SRF))) {
map3d_xy(zaxis_x,zaxis_y,z_max3d + (z_max3d-base_z)/4, &x, &y);
x += zlabel.xoffset * t->h_char;
y += zlabel.yoffset * t->v_char;
strcpy(ss, zlabel.text);
write_multiline(x,y,ss,CENTRE, CENTRE, 0, zlabel.font);
}
}
static void xtick_callback(axis,place,text,grid)
int axis;
double place;
char *text;
int grid; /* linetype or -2 for none */
{
unsigned int x,y,x1,y1;
double scale=(text?ticscale:miniticscale);
int dirn=tic_in?1:-1;
register struct termentry *t = term;
map3d_xy(place, xaxis_y, base_z, &x, &y);
if (grid > -2) {
(*t->linetype)(grid);
/* to save mapping twice, map non-axis y */
map3d_xy(place, y_min3d+y_max3d-xaxis_y, base_z, &x1, &y1);
draw_clip_line(x,y,x1,y1);
(*t->linetype)(-2);
}
if (xtics&TICS_ON_AXIS) {
map3d_xy(place, (y_min3d+y_max3d)/2, base_z, &x, &y);
}
x1=x+tic_unitx*scale*(t->h_tic)*dirn;
y1=y+tic_unity*scale*(t->v_tic)*dirn;
draw_clip_line(x,y,x1,y1);
if (text) {
int just;
if (tic_unitx < -0.9)
just=LEFT;
else if (tic_unitx < 0.9)
just=CENTRE;
else
just=RIGHT;
x1=x-tic_unitx*(t->h_tic)*2;
y1=y-tic_unity*(t->v_tic)*2;
if (!tic_in) {
x1 -= tic_unitx*(t->h_tic)*ticscale;
y1 -= tic_unity*(t->v_tic)*ticscale;
}
clip_put_text_just(x1,y1,text,just);
}
if (xtics & TICS_MIRROR) {
map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x, &y);
x1=x-tic_unitx*scale*(t->h_tic)*dirn;
y1=y-tic_unity*scale*(t->v_tic)*dirn;
draw_clip_line(x,y,x1,y1);
}
}
static void ytick_callback(axis,place,text,grid)
int axis;
double place;
char *text;
int grid;
{
unsigned int x,y,x1,y1;
double scale=(text?ticscale:miniticscale);
int dirn=tic_in?1:-1;
register struct termentry *t = term;
map3d_xy(yaxis_x, place, base_z, &x, &y);
if (grid > -2) {
(*t->linetype)(grid);
map3d_xy(x_min3d+x_max3d-yaxis_x, place, base_z, &x1, &y1);
draw_clip_line(x,y,x1,y1);
(*t->linetype)(-2);
}
if (ytics&TICS_ON_AXIS) {
map3d_xy( (x_min3d+x_max3d)/2, place, base_z, &x, &y);
}
x1=x+tic_unitx*scale*dirn*(t->h_tic);
y1=y+tic_unity*scale*dirn*(t->v_tic);
draw_clip_line(x,y,x1,y1);
if (text) {
int just;
if (tic_unitx < -0.9)
just=LEFT;
else if (tic_unitx < 0.9)
just=CENTRE;
else
just=RIGHT;
x1=x-tic_unitx*(t->h_tic)*2;
y1=y-tic_unity*(t->v_tic)*2;
if (!tic_in) {
x1 -= tic_unitx*(t->h_tic)*ticscale;
y1 -= tic_unity*(t->v_tic)*ticscale;
}
clip_put_text_just(x1,y1,text,just);
}
if (ytics & TICS_MIRROR) {
map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x, &y);
x1=x-tic_unitx*scale*(t->h_tic)*dirn;
y1=y-tic_unity*scale*(t->v_tic)*dirn;
draw_clip_line(x,y,x1,y1);
}
}
static void ztick_callback(axis,place,text,grid)
int axis;
double place;
char *text;
int grid;
{
int len=(text?ticscale:miniticscale)*(tic_in?1:-1)*term->h_tic;
unsigned int x,y;
register struct termentry *t = term;
if (grid > -2) {
unsigned int x1,y1,x2,y2,x3,y3;
double other_x=x_min3d+x_max3d-zaxis_x;
double other_y=y_min3d+y_max3d-zaxis_y;
(*t->linetype)(grid);
map3d_xy(zaxis_x, zaxis_y, place, &x1, &y1);
map3d_xy(back_x, back_y, place, &x2, &y2);
map3d_xy(other_x, other_y, place, &x3, &y3);
draw_clip_line(x1,y1,x2,y2);
draw_clip_line(x2,y2,x3,y3);
(*t->linetype)(-2);
}
map3d_xy(zaxis_x, zaxis_y, place, &x, &y);
draw_clip_line(x,y,x+len, y);
if (text) {
int x1=x-term->h_tic*2;
if (!tic_in)
x1 -= term->h_tic*ticscale;
clip_put_text_just(x1,y,text,RIGHT);
}
if (ztics & TICS_MIRROR) {
double other_x = x_min3d + x_max3d - zaxis_x;
double other_y = y_min3d + y_max3d - zaxis_y;
map3d_xy(other_x, other_y, place, &x, &y);
draw_clip_line(x,y,x-len, y);
}
}
static void map_position(pos, x, y, what)
struct position *pos;
unsigned int *x, *y;
char *what;
{
double xpos=pos->x;
double ypos=pos->y;
double zpos=pos->z;
int screens=0; /* need either 0 or 3 screen co-ordinates */
switch(pos->scalex) {
case first_axes:
case second_axes:
xpos = LogScale(xpos, is_log_x, log_base_log_x, what, "x");
break;
case graph:
xpos=min_array[FIRST_X_AXIS]+xpos*(max_array[FIRST_X_AXIS]-min_array[FIRST_X_AXIS]);
break;
case screen:
++screens;
}
switch(pos->scaley) {
case first_axes:
case second_axes:
ypos = LogScale(ypos, is_log_y, log_base_log_y, what, "y");
break;
case graph:
ypos=min_array[FIRST_Y_AXIS]+ypos*(max_array[FIRST_Y_AXIS]-min_array[FIRST_Y_AXIS]);
break;
case screen:
++screens;
}
switch(pos->scalez) {
case first_axes:
case second_axes:
zpos = LogScale(zpos, is_log_z, log_base_log_z, what, "z");
break;
case graph:
zpos=min_array[FIRST_Z_AXIS]+zpos*(max_array[FIRST_Z_AXIS]-min_array[FIRST_Z_AXIS]);
break;
case screen:
++screens;
}
if (screens==0) {
map3d_xy(xpos,ypos,zpos, x,y);
return;
}
if (screens != 3) {
graph_error("Cannot mix screen co-ordinates with other types");
}
{
register struct termentry *t = term;
*x = pos->x*(t->xmax) + 0.5;
*y = pos->y*(t->ymax) + 0.5;
}
return;
}
static void key_text(xl, yl, text)
int xl, yl;
char *text;
{
if ( key_just == JLEFT && key == -1 ) {
(*term->justify_text)(LEFT);
(*term->put_text)(xl+key_text_left, yl,text);
} else {
if ((*term->justify_text)(RIGHT)) {
if ( key == 1 )
clip_put_text(xl+key_text_right,yl,text);
else
(*term->put_text)(xl+key_text_right,yl,text);
} else {
int x=xl+key_text_right-(term->h_char)*strlen(text);
if (key == 1) {
if (i_inrange(x, xleft, xright))
clip_put_text(x,yl,text);
} else {
(*term->put_text)(x,yl,text);
}
}
}
}
static void key_sample_line(xl, yl)
int xl, yl;
{
if (key == -1) {
(*term->move)(xl+key_sample_left,yl);
(*term->vector)(xl+key_sample_right,yl);
} else {
clip_move(xl+key_sample_left,yl);
clip_vector(xl+key_sample_right,yl);
}
}
static void key_sample_point(xl, yl, pointtype)
int xl, yl;
int pointtype;
{
if (!clip_point(xl+key_point_offset,yl)) {
(*term->point)(xl+key_point_offset,yl, pointtype);
} else {
(*term->point)(xl+key_point_offset,yl, pointtype);
}
}